package com.xiaotu.spider.iqy.pageprocessor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.xiaotu.common.model.TVAreaModel;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.xiaotu.common.exception.SpiderException;
import com.xiaotu.common.exception.SpiderExceptionCode;
import com.xiaotu.common.model.TVPubCommentModel;
import com.xiaotu.common.model.TVRecordModel;
import com.xiaotu.common.model.TVSetsPlotModel;
import com.xiaotu.common.util.Constants;
import com.xiaotu.common.util.HttpUtils;
import com.xiaotu.common.util.KeywordEncode;
import com.xiaotu.common.util.PageUtils;
import com.xiaotu.common.util.RegexUtils;
import com.xiaotu.common.util.StringUtil;
import com.xiaotu.common.util.TVProcessUtils;
import com.xiaotu.spider.APageProcessor;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Request;
import us.codecraft.webmagic.selector.Html;

/**
 * @类名 QIYPageProcessor
 * @日期 2017年2月13日
 * @作者 高海军
 * @功能 爱奇艺网站数据爬取
 */
@Component("IQYPageProcessor")
@Scope("prototype")
public class IQYPageProcessor extends APageProcessor
{
    private static final Logger LOGGER = LoggerFactory
            .getLogger(IQYPageProcessor.class);

    @Override
    protected Request getStartRequest(JSONObject target)
    {
        return new Request("http://so.iqiyi.com/so/q_"
                + KeywordEncode.encode(target.getString("tvName"))
                + "?source=input&sr=246776524452");
    }

    @Override
    protected String getSpiderType()
    {
        return Constants.SpiderTaskType.TV_IQIYI;
    }

    @Override
    public String getPageDataType(Page page)
    {
        String url = page.getUrl().toString();
        if (url.contains("http://so.iqiyi.com/so/q_"))
            return Constants.PageDataType.SEARCH_LIST;
        else if (url.contains("http://up.video.iqiyi.com/ugc-updown/quud.do"))
            return Constants.PageDataType.TV_RECORD;
        else if (url.contains("http://www.iqiyi.com/lib/"))
            return Constants.PageDataType.TV_PLOTSET;
        else if (url.contains("http://api.t.iqiyi.com/qx_api/comment/get_video_comments"))
            return Constants.PageDataType.TV_COMMENT;
        if (url.contains("get_user_profile"))
            return Constants.PageDataType.TV_AUDIENCE;
        if (url.contains("get_province_distribution"))
            return Constants.PageDataType.TV_CITY;
        return Constants.PageDataType.UNKNOW;
    }

    @Override
    public void process(Page page)
    {
        Map<String, Object> tvInfoMap = page.getRequest().getExtras();
        String dataType = this.getPageDataType(page);

        switch (dataType)
        {
            case Constants.PageDataType.SEARCH_LIST:
                this.searchListProcess(page, tvInfoMap);
                break;
            case Constants.PageDataType.TV_RECORD:
                this.tvRecordProcess(page, tvInfoMap);
                break;
            case Constants.PageDataType.TV_PLOTSET:
                this.tvSetsProcess(page, tvInfoMap);
                break;
            case Constants.PageDataType.TV_COMMENT:
                this.tvCommentProcess(page, tvInfoMap);
                break;
            case Constants.PageDataType.TV_AUDIENCE:
                this.peopleProcess(page, tvInfoMap);
                break;
            case Constants.PageDataType.TV_CITY:
                this.areaProcess(page, tvInfoMap);
            default:
                break;
        }
    }

    private void peopleProcess(Page page, Map<String, Object> tvInfoMap)
    {
        PeoplePageProcessor.peopleProcess(page, tvInfoMap.get("tvid") + "");
    }

    private void areaProcess(Page page, Map<String, Object> tvInfoMap)
    {
        List<Map<String, Object>> dataList = PeoplePageProcessor.getCityData(PeoplePageProcessor
                .getDataMap(page));
        String[] areas = dataList.stream().map(map -> map.get("name").toString()).toArray
                (String[]::new);
        String[] values = dataList.stream().map(map -> map.get("value").toString()).toArray
                (String[]::new);
        page.putField(TVAreaModel.class.getName(), new TVAreaModel(tvInfoMap.get("tvid") + "",
                tvInfoMap.get("tvName") + "", areas, values, Constants.SiteName.IQIYI));
    }

    /**
     * 设置已更新集次
     *
     * @param divList
     */
    private TVProcessUtils.UpdateSetGetter getGetter(final List<String> divList)
    {
        return new TVProcessUtils.UpdateSetGetter()
        {
            @Override
            public String getUpdateSet(int idx)
            {
                String divObj = divList.get(idx);
                int end = divObj.lastIndexOf("<i class=\"icon-juji-new\"></i>");
                if (end <= 0)
                    return null;
                int start = divObj.substring(0, end).lastIndexOf(">");
                if (start < 0)
                    return null;
                String set = divObj.substring(start + ">".length(), end).trim();
                if (!RegexUtils.regexMatch(RegexUtils.REGEX_INTEGER, set))
                    return null;
                return set;
            }
        };
    }

    private void searchListProcess(Page page,
            final Map<String, Object> tvInfoMap)
    {
        // 搜索頁面
        final List<String> searchListHTML = page.getHtml()
                .xpath("//div[@class='layout-main']//div[@hoverclick='true']")
                .all();
        List<String> tvnameList = new ArrayList<String>();
        List<String> linkList = new ArrayList<String>();
        final List<String> tvidList = new ArrayList<String>();
        final List<String> albumidList = new ArrayList<String>();
        List<String> tvTypes = new ArrayList<String>();
        List<List<String>> directors = new ArrayList<List<String>>();
        List<List<String>> actors = new ArrayList<List<String>>();
        final List<String> tvSources = new ArrayList<String>();
        for (String htmlStr : searchListHTML)
        {
            Html html = new Html(htmlStr);
            String director = html
                    .xpath("//div[@class='qy-search-result-info half']//a[@data-searchpingback-param='ptype=2-2" +
                            "']/text()")
                    .get();

            if (StringUtil.isEmpty(director))
                continue;
            if (html.xpath("div[@class='icon-tr']//img/@alt").get().contains("预告"))// 预告片
                continue;

            tvnameList.add(html
                    .xpath("//a[@class='main-tit']//span[@class='orange']//text()")
                    .toString());
            linkList.add(html
                    .xpath("//a[@class='qy-mod-link']/@href")
                    .toString());
            tvidList.add(html
                    .xpath("//div[@hoverclick='true']/@data-widget-searchlist-tvid")
                    .toString());
            albumidList.add(html
                    .xpath("//div[@hoverclick='true']/@data-widget-searchlist-albumid")
                    .toString());
            tvTypes.add(html
                    .xpath("//div[@hoverclick='true']/@data-widget-searchlist-catageory")
                    .toString());
            directors.add(html
                    .xpath("//div[@class='qy-search-result-info half']//a[@data-searchpingback-param='ptype=2-2" +
                            "']/text()")
                    .all());
            actors.add(html
                    .xpath("//div[@class='qy-search-result-info half']//a[@data-searchpingback-param='ptype=2-1" +
                            "']/text()")
                    .all());
            tvSources.add(html
                    .xpath("//em[@class='player-name']/text()")
                    .toString().trim());
            
            String firstTime = html
                    .xpath("//em[@class='year']/text()").toString();
            firstTime = RegexUtils.regexSearch(RegexUtils.REGEX_INTEGER, firstTime);
            tvInfoMap.put("firstTime", firstTime);
            
        }

        if (linkList.size() != tvnameList.size()
                || linkList.size() != tvidList.size()
                || linkList.size() != tvTypes.size()
                // || linkList.size() != firstplaytimes.size()
                || linkList.size() != tvSources.size()
                || linkList.size() != albumidList.size()
                || linkList.size() != directors.size()
                || linkList.size() != actors.size())
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);

        TVProcessUtils.addTVFromSearchList(page, tvInfoMap, tvnameList,
                linkList, tvTypes, actors, directors,
                new TVProcessUtils.TVMatcher()
                {
                    @Override
                    protected boolean addTV(Page page,
                            Map<String, Object> tvinfoMap, String name,
                            String tvType, List<String> actorsList,
                            List<String> directorsList, String link, int idx)
                    {
                        String siteName = tvSources.get(idx);
                        if (TVProcessUtils.tvMatched(tvinfoMap, name,
                                TVProcessUtils.getTVType(tvType), actorsList,
                                directorsList)
                                && Constants.SiteName.IQIYI.equals(siteName))
                        {
                            // 添加分集剧情链接
                            // Matcher m =
                            // Pattern.compile("m_([0-9]{9,13}).html")
                            // .matcher(link);
                            // if (m.find())
                            // {
                            // PageUtils.addTargetRequest(page,
                            // "http://www.iqiyi.com/lib/jq_"
                            // + m.group(1) + ".html",
                            // tvinfoMap);
                            // }

                            tvInfoMap.put("pageTVId", tvidList.get(idx));
                            PageUtils.addTargetRequest(page,
                                    "http://up.video.iqiyi.com/ugc-updown/quud.do?dataid="
                                            + albumidList.get(idx)
                                            +
                                            "&type=1&userid=&flashuid" +
                                            "=d6a5b87c879625838bcaa80c88327e3a&appID=21&"
                                            + "callback=window.Q.__callbacks__.cbowbgmp",
                                    tvInfoMap, true);
                            PeoplePageProcessor.addPeopleLink(page, albumidList.get(idx));
                            return true;
                        }
                        return false;
                    }
                }, this.getGetter(searchListHTML));
    }

    private void tvRecordProcess(Page page, Map<String, Object> tvInfoMap)
    {

        String searchList = page.getRawText();
        if (StringUtils.isEmpty(searchList) || !searchList.contains("(")
                || !searchList.contains("catch"))
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);

        searchList = searchList.substring(searchList.indexOf("(") + 1,
                searchList.lastIndexOf("catch") - 2);

        JSONObject jsonObject = JSONObject.fromObject(searchList);

        JSONObject data = jsonObject.getJSONObject("data");

        TVRecordModel record = new TVRecordModel(tvInfoMap.get("tvid") + "",
                TVProcessUtils.getPageTVName(tvInfoMap),
                Constants.SiteName.IQIYI, data.getString("score"), null,
                data.getString("up"), data.getString("down"), null, null,
                TVProcessUtils.getPageUpdateSet(tvInfoMap),tvInfoMap.get("firstTime") + "");
        page.putField(TVRecordModel.class.getName(), record);

        // 获取评论id
        String tvinfo = HttpUtils
                .httpGetJSONP("http://mixer.video.iqiyi.com/jp/mixin/videos/"
                        + tvInfoMap.get("pageTVId")
                        + "?callback=window.Q.__callbacks__.cb7kz35&status=1");
        if (StringUtils.isEmpty(tvinfo) || !tvinfo.contains("(")
                || !tvinfo.contains("catch"))
            return;

        tvinfo = tvinfo.substring(tvinfo.indexOf("(") + 1,
                tvinfo.lastIndexOf("catch") - 3);
        JSONObject tvinfoObject = JSONObject.fromObject(tvinfo);

        if (tvinfoObject == null || tvinfoObject.isEmpty()
                || !tvinfoObject.has("data"))
            return;

        // 视频信息
        JSONObject tvItemObject = tvinfoObject.getJSONObject("data");

        if (!tvItemObject.isEmpty() && tvItemObject.has("playCount"))
        {
            // 播放量
            record.setPlayCount(tvItemObject.getString("playCount"));

            // 评论内容
            PageUtils.addTargetRequest(page,
                    "http://api.t.iqiyi.com/qx_api/comment/get_video_comments?aid="
                            + tvItemObject.getString("qitanId")
                            + "&categoryid=2&cb=fnsucc&escape=true&need_reply=true&need_subject" +
                            "=true&need_total=1&page=1&page_size=10&page_size_reply=3" +
                            "&qitan_comment_type=1&qitancallback=fnsucc&qitanid="
                            + tvItemObject.getString("qitanId")
                            + "&sort=add_time&t=0.0036409597378224134&tvid=0",
                    tvInfoMap);
        }
        else
            LOGGER.warn("[{}] IQY no playcount:{}", this.getSpiderType(),
                    searchList);
    }

    private void tvSetsProcess(Page page, Map<String, Object> tvInfoMap)
    {

        // 添加剧情
        List<TVSetsPlotModel> setsList = new ArrayList<TVSetsPlotModel>();

        List<String> setNoList = page.getHtml()
                .xpath("//ul[@class='mod_page_list']/li[@class='list_item']/h3/a/text()")
                .all();

        List<String> setList = page.getHtml()
                .xpath("//ul[@class='mod_page_list']/li[@class='list_item']/p[@class='list_cont" +
                        "']/text()")
                .all();

        for (int i = 0; i < setList.size(); i++)
        {
            Matcher m = Pattern.compile("第([0-9]{1,3})集")
                    .matcher(setNoList.get(i));
            if (m.find())
                setsList.add(new TVSetsPlotModel(tvInfoMap.get("tvid") + "",
                        tvInfoMap.get("tvName") + "", m.group(1),
                        setList.get(i)));
        }

        if (setsList.isEmpty())
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);
        page.putField(TVSetsPlotModel.class.getName() + "List", setsList);

        List<String> linkList = page.getHtml()
                .xpath("//div[@class='storyLine_page']/ul/li/a/@href").all();
        if (linkList != null && linkList.size() > 1)
        {
            if (page.getUrl().toString().equals(linkList.get(0)))
                PageUtils.addTargetRequests(page,
                        linkList.subList(1, linkList.size()), tvInfoMap);
        }
    }

    private void tvCommentProcess(Page page, Map<String, Object> tvInfoMap)
    {
        String commentListJsonStr = page.getRawText();
        if (StringUtils.isEmpty(commentListJsonStr)
                || !commentListJsonStr.contains("{"))
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);
        commentListJsonStr = commentListJsonStr
                .substring(commentListJsonStr.indexOf("{"));

        JSONObject commentListObject = JSONObject
                .fromObject(commentListJsonStr);
        if (commentListObject == null || commentListObject.isEmpty()
                || !commentListObject.has("data"))
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);

        JSONObject commentObject = commentListObject.getJSONObject("data");
        if (commentObject == null || commentObject.isEmpty()
                || !commentObject.has("comments"))
            throw new SpiderException(
                    SpiderExceptionCode.DataInvalideException);

        JSONArray commentList = commentObject.getJSONArray("comments");

        List<TVPubCommentModel> list = new ArrayList<TVPubCommentModel>();

        for (int i = 0; i < commentList.size(); i++)
        {

            JSONObject comment = commentList.getJSONObject(i);
            String pubtime = comment.getString("addTime");
            if (StringUtils.isEmpty(pubtime))
                continue;
            list.add(new TVPubCommentModel(tvInfoMap.get("tvid") + "",
                    tvInfoMap.get("tvName") + "", Constants.SiteName.IQIYI,
                    comment.getJSONObject("userInfo").getString("uname"),
                    comment.getString("content"),
                    (Long.valueOf(pubtime) * 1000) + "", null, null));
        }

        if (!list.isEmpty())
            page.putField(TVPubCommentModel.class.getName(), list);
    }
}
